using System;
using System.Collections.Generic;

namespace NDomain.Reflection
{
    public class DomainInfo : IDomainInfo
    {
        private string _name;
        private List<ModuleInfo> _modules = new List<ModuleInfo>();

        public DomainInfo(string name)
        {
            _name = name;
        }

        public string Name
        {
            get { return _name; }
        }

        public IList<ModuleInfo> Modules
        {
            get { return _modules.AsReadOnly(); }
        }

        public void NewEntity(string entityPath, string entityName)
        {
            GetModule(entityPath).AddEntity(new EntityInfo(entityName));
        }

        private ModuleInfo GetModule(string entityPath)
        {
            string[] moduleNames = entityPath.Split('.');

            ModuleInfo module = FindOrAdd(moduleNames[0], _modules, _modules.Add);

            for (int i = 1; i < moduleNames.Length;i++ )
                module = FindOrAdd(moduleNames[i], module.Modules, module.AddModule);
            return module;
        }

        private delegate void ModuleAdder(ModuleInfo module);

        private static ModuleInfo FindOrAdd(string moduleName, IList<ModuleInfo> modules, ModuleAdder adder)
        {
            ModuleInfo module = new List<ModuleInfo>(modules).Find(delegate(ModuleInfo m) { return m.Name == moduleName;});
            if (module == null)
            {
                module = new ModuleInfo(moduleName);
                adder(module);
            }
            return module;
        }

        public void NewEntity(string entityPath, string entityName, string aggregateName, bool isAggregateRoot)
        {
            AggregateInfo aggregate = GetModule(entityPath).GetAggregate(aggregateName);
            if (isAggregateRoot)
                aggregate.Root = new EntityInfo(entityName);
            else
                aggregate.AddEntity(new EntityInfo(entityName));
        }

        public void NewValueObject(string valueObjectPath, string valueObjectName)
        {
            GetModule(valueObjectPath).AddValueObject(new ValueObjectInfo(valueObjectName));
        }

        public void NewValueObject(string valueObjectPath, string valueObjectName, string aggregateName)
        {
            GetModule(valueObjectPath).GetAggregate(aggregateName).AddValueObject(new ValueObjectInfo(valueObjectName));
        }

        public void NewService(string servicePath, string serviceName)
        {
            GetModule(servicePath).AddService(new ServiceInfo(serviceName));
        }

        public void NewFactory(string factoryPath, string factoryName, string entityName)
        {
            GetModule(factoryPath).GetEntity(entityName).Factory = new FactoryInfo(factoryName);
        }

        public void NewRepository(string repositoryPath, string repositoryName, string entityName)
        {
            GetModule(repositoryPath).GetEntity(entityName).Repository = new RepositoryInfo(repositoryName);
        }
    }
}